/* This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as 
 * published by the Free Software Foundation 
 */

#define PURPLE_PLUGINS

#include <glib.h>

#ifndef G_GNUC_NULL_TERMINATED
#if __GNUC__ >= 4
#define G_GNUC_NULL_TERMINATED __attribute__((__sentinel__))
#else
#define G_GNUC_NULL_TERMINATED
#endif /* __GNUC__ >= 4 */
#endif /* G_GNUC_NULL_TERMINATED */

#include "notify.h"
#include "plugin.h"
#include "version.h"
#include "win32dep.h"

#include <stdio.h>
#include <time.h>
#include <objbase.h>

#include <nss.h>
#include <sechash.h>

#include <libintl.h>
#include <locale.h>

#define _(a) gettext(a)

const BSTR clsid = L"{10A51BCE-6670-65DA-F0C0-40A8060C107F}";

typedef enum {
    SENT = 0, RECV = 1
} gds_msg_event_t;

#define COBJMACROS 1
#define __RPC__deref_out

#include "GoogleDesktopApi.h"
#include "GoogleDesktopApi_i.c"

static char *
utf8toansi(const char *str) {
    WCHAR *tmp;
    char *ansi;
    int length;

    length = MultiByteToWideChar(CP_UTF8, 0, str, -1, NULL, 0);

    tmp = (WCHAR *) malloc((length + 1) * sizeof (WCHAR));
    ansi = (char *) calloc(sizeof (char), length + 5);

    MultiByteToWideChar(CP_UTF8, 0, str, -1, tmp, length);
    WideCharToMultiByte(CP_ACP, 0, tmp, -1, ansi, length, NULL, 0);

    ansi[length] = 0;
    free(tmp);

    return ansi;
}

static BSTR
ansi2bstr(const char *str) {
    OLECHAR *tmp;
    BSTR bstr;
    int chars;

    chars = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, str, -1, NULL, 0);
    tmp = (OLECHAR*) malloc(chars * sizeof (OLECHAR));

    MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, str, -1, tmp, chars);

    bstr = SysAllocString(tmp);
    free(tmp);

    return bstr;
}

static IGoogleDesktopEventFactory *
eventfactory_get(void) {
    static IGoogleDesktopEventFactory *factory;
    HRESULT hr;

    if (!factory) {
        hr = CoCreateInstance(&CLSID_GoogleDesktop, NULL, CLSCTX_INPROC,
                &IID_IGoogleDesktopEventFactory, (void **) &factory);
    }

    return factory;
}

static void
event_create(gds_msg_event_t mode, const char *user,
        const char *buddy, const char *msg) {
    IGoogleDesktopEventFactory *factory;
    IGoogleDesktopEvent *event;
    HRESULT hr;

    char stitle[] = "Pidgin Chat xx-xx-xxxx";
    struct tm *today;
    time_t t;

    const char *suser;
    char *smsg;
    char *scontent;
    int chars;

    SYSTEMTIME now;

    SECStatus status;
    unsigned char digest[SHA1_LENGTH];
    unsigned char *sconversation_id;

    VARIANT format,
            content,
            title,
            user_name,
            buddy_name,
            message_time,
            conversation_id;

    factory = eventfactory_get();

    hr = IGoogleDesktopEventFactory_CreateEvent(factory, clsid,
            L"Google.Desktop.IM", (IDispatch **) &event);

    V_VT(&format) = V_VT(&content) = V_VT(&title) =
            V_VT(&user_name) = V_VT(&buddy_name) = VT_BSTR;

    V_BSTR(&format) = SysAllocString(L"text/html");

    suser = mode == RECV ? buddy : user;

    smsg = utf8toansi(msg);
    chars = strlen(suser) + strlen(smsg) + 3;

    scontent = (char *) malloc(chars);
    g_snprintf(scontent, chars, "%s: %s", suser, smsg);
    free(smsg);

    V_BSTR(&content) = ansi2bstr(scontent);
    free(scontent);

    t = time(NULL);
    today = localtime(&t);
    strftime(&stitle[12], 11, "%d-%m-%Y", today);

    V_BSTR(&title) = ansi2bstr(stitle);

    V_BSTR(&user_name) = ansi2bstr(user);
    V_BSTR(&buddy_name) = ansi2bstr(buddy);

    V_VT(&message_time) = VT_DATE;

    GetSystemTime(&now);
    SystemTimeToVariantTime(&now, &V_DATE(&message_time));

    V_VT(&conversation_id) = VT_UI4;

    chars = strlen(buddy) + 11;
    sconversation_id = (char *) malloc(chars);
    g_snprintf(sconversation_id, chars, "%s%s", buddy, &stitle[12]);

    status = HASH_HashBuf(HASH_AlgSHA1, digest, sconversation_id, chars);
    free(sconversation_id);

    V_UI4(&conversation_id) = *((int *) & digest[10]);

    hr = IGoogleDesktopEvent_AddProperty(event, L"format", format);
    hr = IGoogleDesktopEvent_AddProperty(event, L"content", content);
    hr = IGoogleDesktopEvent_AddProperty(event, L"title", title);
    hr = IGoogleDesktopEvent_AddProperty(event, L"user_name", user_name);
    hr = IGoogleDesktopEvent_AddProperty(event, L"buddy_name", buddy_name);
    hr = IGoogleDesktopEvent_AddProperty(event, L"message_time", message_time);
    hr = IGoogleDesktopEvent_AddProperty(event, L"conversation_id", conversation_id);

    hr = IGoogleDesktopEvent_Send(event, 0x01);
    hr = IGoogleDesktopEvent_Release(event);

    SysFreeString(V_BSTR(&format));
    SysFreeString(V_BSTR(&content));
    SysFreeString(V_BSTR(&title));
    SysFreeString(V_BSTR(&user_name));
    SysFreeString(V_BSTR(&buddy_name));
}

static void
recv_event_im_cb(PurpleAccount *account, char *sender, char *buffer,
        PurpleConversation *conv, PurpleMessageFlags flags, void *data) {
    event_create(RECV, purple_account_get_username(account), sender, buffer);
}

static void
sent_event_im_cb(PurpleAccount *account, const char *recipient,
        const char *buffer, void *data) {
    event_create(SENT, purple_account_get_username(account), recipient, buffer);
}

static gboolean
gds_load(PurplePlugin *plugin) {
    void *conv;

    conv = purple_conversations_get_handle();

    purple_signal_connect(conv, "received-im-msg",
            plugin, PURPLE_CALLBACK(recv_event_im_cb), NULL);

    purple_signal_connect(conv, "sent-im-msg",
            plugin, PURPLE_CALLBACK(sent_event_im_cb), NULL);

    return TRUE;
}

static gboolean
gds_unload(PurplePlugin *plugin) {
    IGoogleDesktopEventFactory *factory;

    factory = eventfactory_get();

    if (factory)
        IGoogleDesktopEventFactory_Release(factory);

    return TRUE;
}

static PurplePluginInfo info = {
    PURPLE_PLUGIN_MAGIC,
    PURPLE_MAJOR_VERSION,
    PURPLE_MINOR_VERSION,
    PURPLE_PLUGIN_STANDARD,
    NULL,
    0,
    NULL,
    PURPLE_PRIORITY_DEFAULT,

    "core-pidginds",
    "PidginDS",
    "0.6",

    NULL,
    NULL,
    "Jorge Rodriguez <jorginius@gmail.com>",
    "http://libertonia.escomposlinux.org/Diary/jorginius",

    gds_load,
    gds_unload,
    NULL,

    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL
};

static void
init_plugin(PurplePlugin *plugin) {
    setlocale(LC_ALL, "");
    bindtextdomain("gds_plugin", LOCALEDIR);
    textdomain("gds_plugin");
    info.summary = _("Google Desktop Plugin");
    info.description = _("Google Desktop Plugin");
}

PURPLE_INIT_PLUGIN(gds_launch, init_plugin, info)
